home *** CD-ROM | disk | FTP | other *** search
/ BCI NET 2 / BCI NET 2.iso / archives / programming / c / dcback15.lha / dcback.c next >
Encoding:
C/C++ Source or Header  |  1993-04-22  |  13.2 KB  |  425 lines

  1. /*
  2. **      $VER: DCBack.c 1.5 (22.4.93)
  3. **      Auto-detach link library for DICE.
  4. **
  5. **      (C) Copyright 1991-1993 Jaba Development.
  6. **          Written by Jan van den Baard
  7. **/
  8.  
  9. #include <exec/types.h>
  10. #include <exec/memory.h>
  11. #include <exec/execbase.h>
  12. #include <exec/libraries.h>
  13. #include <exec/alerts.h>
  14. #include <dos/dos.h>
  15. #include <dos/dosextens.h>
  16. #include <dos/rdargs.h>
  17. #include <workbench/startup.h>
  18.  
  19. #include <clib/exec_protos.h>
  20. #include <clib/dos_protos.h>
  21.  
  22. #include <stdio.h>
  23. #include <string.h>
  24. #include <fcntl.h>
  25. #include <lib/misc.h>
  26.  
  27. /*
  28.  * --- These globals MUST be defined somewhere in your source!
  29.  */
  30. extern  UBYTE   *_procname;         /* process name */
  31. extern  UBYTE   *_template;         /* commandline template */
  32. extern  UBYTE   *_exthelp;          /* extended command line help */
  33. extern  LONG     _stack;            /* process stack */
  34. extern  LONG     _priority;         /* process priority */
  35. extern  LONG     _BackGroundIO;     /* open background io channel */
  36.  
  37. /*
  38.  * --- externally referenced structures.
  39.  */
  40. extern struct ExecBase  *SysBase;   /* to check for V36 minimum */
  41. extern struct WBStartup *_WBMsg;    /* guess what.... */
  42.  
  43. /*
  44.  * --- This is how both main() and wbmain() are called.
  45.  */
  46. extern long main( long, long * );
  47. extern long wbmain( struct WBStartup * );
  48.  
  49. /*
  50.  * --- Proto for the exit routines and waitwbmsg
  51.  */
  52. long exit( long );
  53. long _exit( long );
  54. void _waitwbmsg( void );
  55.  
  56. /*
  57.  * --- Data that isn't chucked in the BSS section.
  58.  */
  59. BPTR             _DetachDir      =       0l;    /* process current dir */
  60. BPTR             _Backstdout     =       0l;    /* io channel */
  61. UBYTE            _IsDetached     =       FALSE; /* detached flag */
  62. ULONG           *_DosArray       =       0l;    /* commandline array */
  63. UWORD            _NumArgs        =       0l;    /* max # of args */
  64. UBYTE           *_Arguments      =       0l;    /* argument line */
  65. struct RDArgs   *_DosSource      =       0l;    /* for the arguments */
  66.  
  67. /*
  68.  * --- New _main() which checks if it is run from the shell or
  69.  * --- the workbench.
  70.  */
  71. __stkargs long _main( long len, char *lin )
  72. {
  73.     struct Process              *ThisTask;
  74.     struct CommandLineInterface *cli;
  75.     struct MemList              *mlist;
  76.     BPTR                        *SegList, *TmpSeg;
  77.     ULONG                        SegCount = 0l, ArgCount = 0l;
  78.     BYTE                         DetachRun = FALSE;
  79.     UBYTE                       *Tmp;
  80.     ULONG                        alert;
  81.  
  82.    /*
  83.     * --- First we must see wether we are running
  84.     * --- under 2.0 or not. We need 2.0 for the
  85.     * --- commandline parsing!
  86.     */
  87.     if ((( struct Library *)SysBase)->lib_Version < 36 )
  88.         return( RETURN_FAIL );
  89.  
  90.    /*
  91.     * --- Get a pointer to our Task (Process)
  92.     */
  93.     ThisTask = ( struct Process * )SysBase->ThisTask;
  94.  
  95.    /*
  96.     * --- When run from the shell the process has
  97.     * --- a CLI structure. If this is the case
  98.     * --- the 'DetachRun' flag is set to TRUE so we
  99.     * --- we know that the program still has to be
  100.     * --- detached.
  101.     */
  102.     if ( ThisTask->pr_CLI )
  103.         DetachRun = TRUE;
  104.  
  105.    /*
  106.     * --- When either the 'DetachRun' or '_IsDetached' flag
  107.     * --- is TRUE it means that we are run from the shell.
  108.     */
  109.     if ( DetachRun || _IsDetached ) {
  110.        /*
  111.         * --- Check if we are detached yet...
  112.         */
  113.         if ( ! _IsDetached ) {
  114.            /*
  115.             * --- We arn't detached yet so we must parse
  116.             * --- the arguments given to us by the shell.
  117.             */
  118.             if ( Tmp = _template ) {
  119.                /*
  120.                 * --- There is a template string supplied
  121.                 */
  122.                 if ( *Tmp ) {
  123.                    /*
  124.                     * --- The template string even got characters in it!
  125.                     * --- Now we must count the maximum number of arguments
  126.                     * --- we can expect. This is done by counting the
  127.                     * --- commas in the template string and then adding
  128.                     * --- one to the result
  129.                     */
  130.                     while ( *Tmp ) {
  131.                         if ( *Tmp == ',' ) ArgCount++;
  132.                         Tmp++;
  133.                     }
  134.                     ArgCount++;
  135.                 }
  136.             }
  137.  
  138.            /*
  139.             * --- Allocate and parse the arguments.
  140.             */
  141.             if ( ArgCount ) {
  142.                /*
  143.                 * --- There are arguments to be expected.
  144.                 */
  145.                 _NumArgs   = ArgCount; /* save argument count */
  146.                 _Arguments = lin;      /* save the argument line pointer */
  147.  
  148.                /*
  149.                 * --- Allocate our RDArgs structure.
  150.                 */
  151.                 if ( ! ( _DosSource = ( struct RDArgs * )AllocVec((long)sizeof( struct RDArgs ), MEMF_PUBLIC | MEMF_CLEAR ))) {
  152.                     alert = AT_Recovery | AG_NoMemory | AO_Unknown;
  153.                     goto suError;
  154.                 }
  155.  
  156.                /*
  157.                 * --- Setup the RDArgs structure for extended help.
  158.                 */
  159.                 _DosSource->RDA_ExtHelp          = _exthelp;
  160.  
  161.                /*
  162.                 * --- Try to allocate the array that will hold
  163.                 * --- the result of the parse.
  164.                 */
  165.                 if ( ! (_DosArray = (ULONG *)AllocVec( ArgCount * sizeof( LONG ), MEMF_PUBLIC | MEMF_CLEAR ))) {
  166.                     alert = AT_Recovery | AG_NoMemory | AO_Unknown;
  167.                     goto suError;
  168.                 }
  169.  
  170.                /*
  171.                 * --- Try to parse the arguments from STDIN.
  172.                 */
  173.                 if ( ! ReadArgs( _template, _DosArray, _DosSource )) {
  174.                     PrintFault( IoErr(), NULL );
  175.                     alert = 0l;
  176.                     goto suError;
  177.                 }
  178.             }
  179.         }
  180.  
  181.        /*
  182.         * --- This code only get's executed when the program
  183.         * --- was started from the shell and isn't detached yet.
  184.         */
  185.         if ( cli = ( struct CommandLineInterface * )BADDR( ThisTask->pr_CLI )) {
  186.            /*
  187.             * --- Get a copy of the lock to the current directory
  188.             */
  189.             CurrentDir( _DetachDir = CurrentDir( 0l ));
  190.             _DetachDir = DupLock( _DetachDir );
  191.  
  192.            /*
  193.             * --- Mark us as detached ( a little premature but so what.. )
  194.             */
  195.             _IsDetached = TRUE;
  196.  
  197.            /*
  198.             * --- Open a io channel if requested
  199.             */
  200.             if ( _BackGroundIO )
  201.                 _Backstdout = Open( "*", MODE_OLDFILE );
  202.  
  203.            /*
  204.             * --- Sanity check. If the stack is 0 then make the stack 4096
  205.             */
  206.             if ( ! _stack )
  207.                 _stack = 4096l;
  208.  
  209.            /*
  210.             * --- Clear processor caches.
  211.             */
  212.             CacheClearU();
  213.  
  214.            /*
  215.             * --- Try to launch us as a non-cli process
  216.             */
  217.             if ( CreateProc(  _procname, _priority, cli->cli_Module, _stack )) {
  218.                /*
  219.                 * --- Don't rip the code out from under us
  220.                 */
  221.                 cli->cli_Module = 0l;
  222.  
  223.                /*
  224.                 * --- We must make sure that dos doesn't deallocate
  225.                 * --- our arguments before we get a chance to use
  226.                 * --- them.
  227.                 */
  228.                 SetArgStr( 0l );
  229.  
  230.                 return ( RETURN_OK );
  231.             } else {
  232.                 alert = AT_Recovery | AG_ProcCreate | AO_Unknown;
  233.                 goto suError;
  234.             }
  235.         } else {
  236.            /*
  237.             * --- Getting here means that we now run as a non-cli
  238.             * --- process initially started from a shell.
  239.             */
  240.             if ( ! strcmp( ThisTask->pr_Task.tc_Node.ln_Name, _procname )) {
  241.  
  242.                /*
  243.                 * --- Now we are running detached we must make sure that
  244.                 * --- dos deallocates the commandline (if there) when
  245.                 * --- we exit.
  246.                 */
  247.                 SetArgStr( _Arguments );
  248.  
  249.                /*
  250.                 * --- Now we must make sure that we get deallocated
  251.                 * --- when the program exits. This is done by creating
  252.                 * --- a MemList with pointers to all our segments in
  253.                 * --- it and then AddTail'ing this to the Task it's
  254.                 * --- MemList which automatically get's deallocated
  255.                 * --- by the system.
  256.                 */
  257.                 SegList = ( BPTR * )BADDR( ThisTask->pr_SegList );
  258.                 SegList = ( BPTR * )BADDR( SegList[3] );
  259.                 TmpSeg  = SegList;
  260.  
  261.                /*
  262.                 * --- Count the number of segments we have.
  263.                 */
  264.                 while ( SegList ) {
  265.                     SegList = ( BPTR * )BADDR( *SegList );
  266.                     SegCount++;
  267.                 }
  268.  
  269.                /*
  270.                 * --- Try to allocate a MemList with enough MemEntry's
  271.                 * --- I didn't use AllocVec because the system deallocates
  272.                 * --- this structure itself with FreeMem() and not FreeVec()
  273.                 * --- (I think........)
  274.                 */
  275.                 if ( mlist = ( struct MemList * )AllocMem( sizeof( struct MemList ) + sizeof( struct MemEntry ) * ( SegCount - 1 ), MEMF_PUBLIC | MEMF_CLEAR )) {
  276.  
  277.                     SegList  = TmpSeg;
  278.                     mlist->ml_NumEntries = SegCount;
  279.                     SegCount = 0l;
  280.  
  281.                    /*
  282.                     * --- Initialize all MemEntries
  283.                     */
  284.                     while ( SegList ) {
  285.                         mlist->ml_me[ SegCount ].me_Addr   = (APTR)&SegList[ -1 ];
  286.                         mlist->ml_me[ SegCount ].me_Length = SegList[ -1 ];
  287.                         SegList = ( BPTR * )BADDR( *SegList );
  288.                         SegCount++;
  289.                     }
  290.  
  291.                    /*
  292.                     * --- Add our MemList to the Task it's MemList.
  293.                     */
  294.                     Forbid();
  295.                     AddTail( &ThisTask->pr_Task.tc_MemEntry, &mlist->ml_Node );
  296.                     Permit();
  297.  
  298.                    /*
  299.                     * --- Set our current dir
  300.                     */
  301.                     CurrentDir( _DetachDir );
  302.  
  303.                    /*
  304.                     * --- If an io channel was requested we must
  305.                     * --- initialize the proper stdio structures
  306.                     */
  307.                     if ( _BackGroundIO ) {
  308.                         ThisTask->pr_COS = _Backstdout;
  309.  
  310.                         _IoStaticFD[1].fd_Fh    =   _Backstdout;
  311.                         _IoStaticFD[1].fd_Flags =   O_RDWR | O_NOCLOSE | O_ISOPEN;
  312.                         _IoStaticFD[2].fd_Fh    =   _Backstdout;
  313.                         _IoStaticFD[2].fd_Flags =   O_RDWR | O_NOCLOSE | O_ISOPEN;
  314.  
  315.                         _finitdesc( stdout,  1, __SIF_WRITE | __SIF_NOFREE );
  316.                         _finitdesc( stderr,  2, __SIF_WRITE | __SIF_NOFREE );
  317.                     }
  318.  
  319.                    /*
  320.                     * --- Now we just exit with whatever main()
  321.                     * --- returns to us.
  322.                     */
  323.                     exit( main( (long)_NumArgs, _DosArray ));
  324.  
  325.                 } else {
  326.                     alert = AT_Recovery | AG_NoMemory | AO_Unknown;
  327.                     goto suError;
  328.                 }
  329.             }
  330.         }
  331.     } else {
  332.        /*
  333.         * --- Getting here means we have been started from the workbench.
  334.         */
  335.         if ( _WBMsg->sm_ArgList )
  336.            /*
  337.             * --- CurrentDir to the directory we are started from
  338.             */
  339.             CurrentDir( _WBMsg->sm_ArgList->wa_Lock );
  340.  
  341.        /*
  342.         * --- Now we just exit with whatever wbmain()
  343.         * --- returns to us.
  344.         */
  345.         exit( wbmain( _WBMsg ));
  346.     }
  347.  
  348.    /*
  349.     * --- This is never called! It just brings in the code that
  350.     * --- waits for the Workbench message for when we are started
  351.     * --- from the workbench! See wbmain.a!
  352.     */
  353.     _waitwbmsg();
  354.  
  355.    /*
  356.     * --- Here's where we land when something failed.
  357.     * --- This cleans up the mess we made except when we
  358.     * --- got here because the MemList could not be
  359.     * --- allocated! If that's the case the segments wont
  360.     * --- be deallocated. This shouldn't be a problem
  361.     * --- because when the MemList cannot be allocated anymore
  362.     * --- your system is really fuc#@$$##@ up!
  363.     */
  364. suError:
  365.     if ( _DosSource ) {
  366.         FreeArgs( _DosSource );
  367.         FreeVec( _DosSource );
  368.     }
  369.     if ( _DosArray )    FreeVec( _DosArray );
  370.     if ( _DetachDir )   UnLock( _DetachDir );
  371.     if ( alert )        Alert( alert );
  372.     return( RETURN_FAIL );
  373. }
  374.  
  375. #include <lib/atexit.h>
  376.  
  377. typedef struct Process Process;
  378.  
  379. AtExit *_ExitBase;
  380.  
  381. /*
  382.  * --- A New exit which cleans up the mess we made.
  383.  */
  384. long exit( long code )
  385. {
  386.     AtExit *eb;
  387.  
  388.    /*
  389.     * --- If opened, close the io channel
  390.     */
  391.     if ( _Backstdout )
  392.         Close( _Backstdout );
  393.  
  394.    /*
  395.     * --- UnLock our current dir
  396.     */
  397.     if ( _DetachDir )
  398.         UnLock( _DetachDir );
  399.  
  400.    /*
  401.     * --- Deallocate our argument array
  402.     */
  403.     if ( _DosArray )
  404.         FreeVec( _DosArray );
  405.  
  406.    /*
  407.     * --- Cleanup our RDArgs structure
  408.     */
  409.     if ( _DosSource ) {
  410.         FreeArgs( _DosSource );
  411.         FreeVec( _DosSource );
  412.     }
  413.  
  414.    /*
  415.     * --- Ask Matthew...... I don't know!
  416.     */
  417.     for (eb = _ExitBase; eb; eb = eb->Next)
  418.         (*eb->Func)();
  419.  
  420.    /*
  421.     * --- Low level exit
  422.     */
  423.     _exit(code);
  424. }
  425.